#pragma once
#include "Tcpserve.hpp"
#include "Util.hpp"
#include <sstream>
std::string baotousep(" ");
std::string keyvaluesep(": ");
std::string blanksep("\r\n");
std::string webroot("./wwwroot");
std::string homepage("/index.html");
class Request
{
public:
    Request() : _is_interact(false)
    {
    }

    std::string Serialize()
    {
        return " ";
    }
    void ParseReqLine(std::string &reqline)
    {
        std::stringstream ss(reqline);
        ss >> this->_method >> this->_uri >> this->_version;
    }
    bool Deserialize(std::string &reqstr)
    {
        // 首先我们先提取我们的请求行
        // std::cout<<reqstr<<std::endl;
        std::string reqline;
        bool res = Util::ReadOneLine(reqstr, &reqline, blanksep);
        if (!res)
            return false;
        LOG(LogLevel::DEBUG) << reqline;
        // std::cout<<reqstr<<std::endl;
        // 对请求行进行序列化
        ParseReqLine(reqline);
        //已经转化为了web根目录下的路径
        if (_uri == "/")
            _uri = webroot + homepage;
        else
            _uri = webroot + _uri;
        LOG(LogLevel::DEBUG) << "_method=" << _method;
        LOG(LogLevel::DEBUG) << "_uri=" << _uri;
        LOG(LogLevel::DEBUG) << "_version=" << _version;
        const std::string temp = "?";
        auto pos = _uri.find(temp);
        // 没有提交的参数
        if (pos == std::string::npos)
        {
            return true;
        }
        // 走到这里一定是提交参数的申请的时动态资源
        _is_interact = true;
        _args = _uri.substr(pos + temp.size());
        _uri = _uri.substr(0, pos);
        LOG(LogLevel::DEBUG) << "_method=" << _method;
        LOG(LogLevel::DEBUG) << "_uri=" << _uri;
        LOG(LogLevel::DEBUG) << "_version=" << _version;
        return true;
    }
    ~Request()
    {
    }
    std::string URI()
    {
        return _uri;
    }
    bool isInteract()
    {
        return _is_interact;
    }
    std::string Args()
    {
        return _args;
    }

private:
    // 请求行
    std::string _method;
    std::string _uri; // 访问的web根目录的路径
    std::string _version;

    // 下面的报头
    std::unordered_map<std::string, std::string> _headers;
    // 空行
    std::string _blankline;
    // 正文
    // 请求行会把参数通过uri进行提交 get
    // post会放在文本里面
    std::string _text;

    // 用来存储参数
    std::string _args;
    // 判断是否是交互的
    bool _is_interact;
};

class Response
{
public:
    Response() : _blankline(blanksep), _version("HTTP/1.1")
    {
    }
    ~Response()
    {
    }
    void SetTargetFile(const std::string &target)
    {
        _targetfile = target;
    }
    std::string Serialize()
    {
        std::string reqline = _version + baotousep + std::to_string(_code) + _desc + blanksep;
        std::string secondline;
        for (auto &ch : _headers)
        {
            std::string key = ch.first;
            std::string value = ch.second;
            secondline += key + keyvaluesep + value + blanksep;
        }
        return reqline + secondline + _blankline + _text;
    }
    void SetText(std::string te)
    {
        _text=te;
    }
    void SetCode(int code)
    {
        _code = code;
        switch (_code)
        {
        case 200:
            _desc = "OK";
            break;
        case 404:
            _desc = "Not Found";
            break;
        default:
            break;
        }
    }
    bool SetHeaders(std::string key, std::string val)
    {
        auto pos = _headers.find(key);
        if (pos != _headers.end())
        {
            return false;
        }
        _headers.insert(make_pair(key, val));
        return true;
    }
    std::string Uri2Suffix(std::string filename)
    {
        // 提取后缀
        auto pos = filename.rfind('.');
        if (pos == std::string::npos)
            return "";
        std::string format = filename.substr(pos);
        if (format == ".mp3")
            return "audio/mp3";
        else if (format == ".html")
            return "text/html";
        else if (format == ".jpeg")
            return "image/jpeg";
        else if (format == ".mp4")
            return "video/mp4";
        else if (format == ".jpg")
            return "application/x-jpg";
        else if (format == ".img")
            return "application/x-img";
        else if (format == ".png")
            return "application/x-png";
        else
            return "";
    }
    bool MakeResponse()
    {

        // 去读取目标文件的资源
        bool res = Util::ReadFileContent(_targetfile, &_text);
        if (!res)
        {
            // _text = "";
            // SetCode(404);
            // _targetfile = webroot + "/404.html";
            // int filesize = Util::FileSize(_targetfile);
            // Util::ReadFileContent(_targetfile, &_text);
            // std::string suffix = Uri2Suffix(_targetfile);
            // SetHeaders("Content-Length", std::to_string(filesize));
            // SetHeaders("Content-Type", suffix);
            // return false;

            // 重定向Location就是位置去向 永久重定向和我们的暂时重定向就只有搜索引擎的影响
             SetCode(302);
             SetHeaders("Location","http://116.205.122.71:8081/404.html");
             return true;
        }
        else
        {
            SetCode(200);
            int filesize = Util::FileSize(_targetfile);
            std::string suffix = Uri2Suffix(_targetfile);
            SetHeaders("Content-Length", std::to_string(filesize));
            SetHeaders("Content-Type", suffix);
            SetHeaders("Set-Cookie","username=123; ");
        }
        return true;
    }
    bool Deserialize(std::string &reqstr)
    {
        return true;
    }
    std::string GetText()
    {
        return _text;
    }

private:
    std::string _version;
    int _code;         // 404
    std::string _desc; // "Not Found"

    std::unordered_map<std::string, std::string> _headers;
    std::string _blankline;
    std::string _text;

    // 其他属性
    std::string _targetfile;
};

using func_t1 = std::function<void(Request &req, Response &res)>;
class Http
{
public:
    Http(uint16_t port) : tsvp(std::make_unique<TcpServe>(port))
    {
    }
    void Hander(std::shared_ptr<Socket> sockfd, InetAddr peer)
    {
        // 进行读文件
        std::string buffer;
        int n = sockfd->Recive(&buffer);
        std::cout << buffer << std::endl;
        // 这里不可以保证读取到的是一个完整的报文
        // 这里我们假设读取到了一个完整报文

        // 现在我们要进行反序列化设置我们的请求结构并拿到我们的请求行
        // std::cout<<buffer<<std::endl;
        if (n > 0)
        {
            std::cout << "##########################" << std::endl;
            std::cout << buffer;
            std::cout << "##########################" << std::endl;
            // 拿到请求行
            Request req;
            Response res;
            req.Deserialize(buffer);
            if (req.isInteract())
            {
                if(_route.find(req.URI())==_route.end())
                {
                    //找不到提供的服务
                    LOG(LogLevel::DEBUG)<<"找不到动态服务:"<<req.URI();
                    res.SetCode(302);
                    res.SetHeaders("Location","http://116.205.122.71:8081/404.html");
                    sockfd->Send(res.Serialize());
                }
                else
                {
                    LOG(LogLevel::DEBUG)<<req.URI();
                    //可以找到提供的服务去调用服务返回
                    _route[req.URI()](req,res);
                    sockfd->Send(res.Serialize());
                }
            }
            else
            {
                // 访问静态资源
                res.SetTargetFile(req.URI());
                // 服务端去访问静态资源因此我们的应答中因该有一个静态资源的路径的属性
                res.MakeResponse();
                // 序列化后通过网络进行发送
                sockfd->Send(res.Serialize());
            }

            // 拿到我们要访问的资源路径并构建应答返回给我们的客户端

            // 下面我们要去访问我们的资源路径
        }
    }
    void Start()
    {
        tsvp->Start([this](std::shared_ptr<Socket> sockfd, InetAddr peer)
                    { this->Hander(sockfd, peer); });
    }
    void RegisterService(const std::string name, func_t1 h)
    {
        std::string key = webroot + name; // ./wwwroot/login
        auto iter = _route.find(key);
        if (iter == _route.end())
        {
            _route.insert(std::make_pair(key, h));
        }
    }
    ~Http()
    {
    }

private:
    std::unique_ptr<TcpServe> tsvp;
    // 把业务逻辑交给上层 有我们的上层进行方法的注册 由协议层调用业务层的服务
    std::unordered_map<std::string, func_t1> _route;
};
